package com.modules.utils;

import com.modules.model.TreeNode;
import com.modules.model.Treeable;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Method;
import java.util.*;

/**
 * Created by lewis on 2017/8/30.
 */
public class TreeUtils {
    public static final Boolean	LAYUI_TREE_STATUS_CLOSED	= false;
    public static final Boolean	LAYUI_TREE_STATUS_OPEN		= true;

    /**
     * 转换实现Treeable接口的实体对象成Tree对象格式TreeNode
     *
     * @param src
     *            要转换的源对象集合
     * @param target
     *            转换后的TreeNode集合
     * @param
     *
     *
     *
     */
    @SuppressWarnings("unchecked")
    public static void parse(final List<?> src, List<TreeNode> target, final boolean lazy)  {
        if (null != src && src.size() > 0) {
            Object first = src.get(0);
            //AssertUtils.isInstanceOf(Treeable.class, first, "src is not implements Treeable.");

            if (null != first && first instanceof Treeable) {
                for (Object entity : src) {
                    Treeable itemSource = ((Treeable) entity);
                    TreeNode tv = new TreeNode();
                    tv.setId(itemSource.getId());
                    tv.setName(itemSource.getText());
                    tv.setTitle(itemSource.getText());
                    //tv.setHref(itemSource.getHref());
                    tv.setUrl(itemSource.getUrl());
                    tv.setIcon(itemSource.getIcon());
                    target.add(tv);

                    List children = itemSource.getChildren();
                    if (null != children && children.size() > 0) {
                        tv.setSpread(LAYUI_TREE_STATUS_CLOSED);
                        if (!lazy) {
                            List<TreeNode> lstChildren = new ArrayList<TreeNode>();
                            parse(children, lstChildren, lazy);
                            tv.getChildren().addAll(lstChildren);
                        }
                    } else {
                        tv.setSpread(LAYUI_TREE_STATUS_OPEN);
                    }
                }
            }
        }
    }

    /**
     * 用于报表中只显示一级节点
     * @param src
     * @param target
     * @throws Exception
     */
    public static void parse(final List<?> src, List<TreeNode> target) throws Exception {
        if (null != src && src.size() > 0) {
            Object first = src.get(0);
            //AssertUtils.isInstanceOf(Treeable.class, first, "src is not implements Treeable.");

            if (null != first && first instanceof Treeable) {
                for (Object entity : src) {
                    Treeable itemSource = ((Treeable) entity);
                    TreeNode tv = new TreeNode();
                    tv.setId(itemSource.getId());
                    tv.setName(itemSource.getText());
                    //tv.setHref(itemSource.getHref());
                    tv.setTitle(itemSource.getText());
                    tv.setUrl(itemSource.getUrl());
                    tv.setIcon(itemSource.getIcon());
                    target.add(tv);
                    tv.setSpread(LAYUI_TREE_STATUS_OPEN);
                }
            }
        }
    }

    /**
     * 转换实现Treeable接口的实体对象成Tree对象格式TreeNode,包含附加的实体对象attributes<br>
     * eg.<br>
     * TreeUtils.parse(menus, target, false, "menuPath", "delflag");
     *
     * @param src
     *            要转换的源对象集合
     * @param target
     *            转换后的TreeNode集合
     * @param
     *
     * @param attributes
     *            需要追加到TreeNode上的attributes
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public static void parse(final List<?> src, List<TreeNode> target, final boolean lazy, String... attributes) throws Exception {
        if (null != src && src.size() > 0) {
            Object first = src.get(0);
            //AssertUtils.isInstanceOf(Treeable.class, first, "src is not implements Treeable.");

            if (null != first && first instanceof Treeable) {
                for (Object entity : src) {
                    TreeNode tv = new TreeNode();

                    if (attributes != null) {
                        //tv.setAttributes(new NodeAttributes());
                        tv.setAttributes(toJson(entity, attributes));
                    }

                    Treeable itemSource = ((Treeable) entity);
                    tv.setId(itemSource.getId());
                    tv.setName(itemSource.getText());
                    //tv.setHref(itemSource.getHref());
                    tv.setTitle(itemSource.getText());
                    tv.setUrl(itemSource.getUrl());
                    tv.setIcon(itemSource.getIcon());
                    target.add(tv);

                    List childs = itemSource.getChildren();
                    if (null != childs && childs.size() > 0) {
                        tv.setSpread(LAYUI_TREE_STATUS_CLOSED);
                        if (!lazy) {
                            List<TreeNode> children = new ArrayList<TreeNode>();
                            parse(childs, children, lazy, attributes);
                            tv.getChildren().addAll(children);
                        }
                    } else {
                        tv.setSpread(LAYUI_TREE_STATUS_OPEN);
                    }
                }
            }
        }
    }


    /**
     * 转换实现Treeable接口的实体对象成Tree对象格式TreeNode
     * 支持延迟加载
     * @param src
     *            要转换的源对象集合
     * @param target
     *            转换后的TreeNode集合
     * @param

     */
    @SuppressWarnings("unchecked")
    public static void parseEx(final List<?> src, List<TreeNode> target, final boolean lazy) throws Exception {
        if (null != src && src.size() > 0) {
            Object first = src.get(0);
            //AssertUtils.isInstanceOf(Treeable.class, first, "src is not implements Treeable.");

            if (null != first && first instanceof Treeable) {
                for (Object entity : src) {
                    Treeable itemSource = ((Treeable) entity);
                    TreeNode tv = new TreeNode();
                    tv.setId(itemSource.getId());
                    tv.setName(itemSource.getText());
                    //tv.setHref(itemSource.getHref());
                    tv.setTitle(itemSource.getText());
                    tv.setUrl(itemSource.getUrl());
                    tv.setIcon(itemSource.getIcon());
                    target.add(tv);

					/*lazy 为 true ,延迟加载*/
                    if(lazy)
                    {
                        tv.setSpread(LAYUI_TREE_STATUS_CLOSED);
                        continue;
                    }

                    List children = itemSource.getChildren();
                    if (null != children && children.size() > 0) {
                        tv.setSpread(LAYUI_TREE_STATUS_CLOSED);
                        if (!lazy) {
                            List<TreeNode> lstChildren = new ArrayList<TreeNode>();
                            parse(children, lstChildren, lazy);
                            tv.getChildren().addAll(lstChildren);
                        }
                    } else {
                        tv.setSpread(LAYUI_TREE_STATUS_OPEN);
                    }
                }
            }
        }
    }

    /**
     * 转换实现Treeable接口的实体对象成Tree对象格式TreeNode,包含附加的实体对象attributes<br>
     * 支持延迟加载
     * eg.<br>
     * TreeUtils.parse(menus, target, false, "menuPath", "delflag");
     *
     * @param src
     *            要转换的源对象集合
     * @param target
     *            转换后的TreeNode集合
     * @param
     *
     * @param attributes

     */
    @SuppressWarnings("unchecked")
    public static void parseEx(final List<?> src, List<TreeNode> target, final boolean lazy, String... attributes) throws Exception {
        if (null != src && src.size() > 0) {
            Object first = src.get(0);
            //AssertUtils.isInstanceOf(Treeable.class, first, "src is not implements Treeable.");

            if (null != first && first instanceof Treeable) {
                for (Object entity : src) {
                    TreeNode tv = new TreeNode();

                    if (attributes != null) {
                        //tv.setAttributes(new NodeAttributes());
                        tv.setAttributes(toJson(entity, attributes));
                    }

                    Treeable itemSource = ((Treeable) entity);
                    tv.setId(itemSource.getId());
                    tv.setName(itemSource.getText());
                    //tv.setHref(itemSource.getHref());
                    tv.setTitle(itemSource.getText());
                    tv.setUrl(itemSource.getUrl());
                    tv.setIcon(itemSource.getIcon());
                    target.add(tv);

					/*lazy 为 true ,延迟加载*/
                    if(lazy)
                    {
                        tv.setSpread(LAYUI_TREE_STATUS_CLOSED);
                        continue;
                    }

                    List childs = itemSource.getChildren();
                    if (null != childs && childs.size() > 0) {
                        tv.setSpread(LAYUI_TREE_STATUS_CLOSED);
                        if (!lazy) {
                            List<TreeNode> children = new ArrayList<TreeNode>();
                            parse(childs, children, lazy, attributes);
                            tv.getChildren().addAll(children);
                        }
                    } else {
                        tv.setSpread(LAYUI_TREE_STATUS_OPEN);
                    }
                }
            }
        }
    }

    private static Map<String, Object> toJson(Object entity, String... attributes) throws Exception {
        Map<String, Object> target = new HashMap<String, Object>();

        Class clazz = entity.getClass();
        try {
            for (String fieldName : attributes) {
                //Field field = clazz.getField(fieldName);
                Method method = clazz.getMethod("get" + StringUtils.capitalize(fieldName), null);
                target.put(fieldName, method.invoke(entity, null));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return target;
    }

    public static void main(String[] args) {
        Object o = new Object();

    }

    /**
     *
     * @Title: parseMenu
     * @Description:将菜单的list转换成easyui接受的数据结构。
     *
     * @param src
     *            包含所有节点以及需要的数据
     * @param target
     */
    public static void parseTree(final List<?> src, List<TreeNode> target, String... attributes) throws Exception {
        if (src == null || src.size() == 0) {
            return;
        }
        //将传入的平面list转换成map，key值为parent，value为treenode为元素的list
        Map<String, ?> map = makeMap(src, attributes);
        List<TreeNode> roots = (List) map.get(null);
        if (roots != null) {
            setChildren(map, roots);
            for (TreeNode root : roots) {
                target.add(root);
            }
        } else {
            if(map != null){
                Iterator it = map.entrySet().iterator();
                while(it.hasNext()){
                    Map.Entry entry = (Map.Entry)it.next();
                    List<TreeNode> nodes = (List)entry.getValue();
                    setChildren(map, nodes);
                    for (TreeNode node : nodes) {
                        target.add(node);
                    }
                }
            }
        }
    }


    /**
     * 机构数转换
     * @param src 源
     * @param target 目标
     * @param rootElement 根节点
     * @param attributes 其他属性
     * @throws Exception
     * @since 2014年5月29日@ChengDu
     * @author Halcyon.Li
     * @version v1.0
     */
    public static void parseTree(final List<?> src, List<TreeNode> target, Treeable rootElement, String... attributes) throws Exception {
        if (src == null || src.size() == 0) {
            return;
        }
        //将传入的平面list转换成map，key值为parent，value为treenode为元素的list
        Map<String, ?> map = makeMap(src, attributes);
        List<TreeNode> roots = (List) map.get(null);
        if (roots != null) {
            setChildren(map, roots);
            for (TreeNode root : roots) {
                target.add(root);
            }
        } else {
            if (map != null) {
                List<TreeNode> nodes = (List<TreeNode>)map.get(rootElement.getParent());
                setChildren(map, nodes);
                for (TreeNode node : nodes) {
                    target.add(node);
                }
            }
        }
    }

    private static Map<String, ?> makeMap(final List<?> src, String... attributes) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
        List<TreeNode> mapElementlist = new ArrayList<TreeNode>();
        //将传入的平面list转换成map，key值为parent，value为treenode为元素的list
        for (int i = 0; i < src.size(); i++) {
            Treeable treeNode = (Treeable) src.get(i);
            String parent = treeNode.getParent();
            if (map.containsKey(parent)) {
                mapElementlist = (List<TreeNode>) map.get(parent);
                TreeNode node = new TreeNode();
                node.setId(treeNode.getId());
                node.setName(treeNode.getText());
                //node.setHref(treeNode.getHref());
                node.setTitle(treeNode.getText());
                node.setUrl(treeNode.getUrl());
                node.setIcon(treeNode.getIcon());

                if (attributes != null) {
                    node.setAttributes(toJson(treeNode, attributes));
                }

                mapElementlist.add(node);
            } else {
                List<TreeNode> list = new ArrayList<TreeNode>();
                TreeNode node = new TreeNode();
                node.setId(treeNode.getId());
                node.setName(treeNode.getText());
                //node.setHref(treeNode.getHref());
                node.setTitle(treeNode.getText());
                node.setUrl(treeNode.getUrl());
                node.setIcon(treeNode.getIcon());
                if (attributes != null) {
                    node.setAttributes(toJson(treeNode, attributes));
                }
                list.add(node);
                map.put(parent, list);
            }
        }
        return map;
    }

    private static void setChildren(Map map, List list) {
        for (int i = 0; i < list.size(); i++) {
            TreeNode node = (TreeNode) list.get(i);
            String nodeId = node.getId();
            //该节点的id存在在map中，则有子节点
            if (map.containsKey(nodeId)) {
                List children = (List) map.get(nodeId);
                node.setChildren(children);
                node.setSpread(LAYUI_TREE_STATUS_CLOSED);

                setChildren(map, children);
            }
            //该节点为叶子节点
            else {
                node.setSpread(LAYUI_TREE_STATUS_OPEN);
            }
        }
    }
}

